<!DOCTYPE html>
<html>

<head>
    <title>custom trip </title>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/dat.gui@0.7.6/build/dat.gui.min.js"></script>
    <link type="text/css" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/maptalks/dist/maptalks.css">
    <script type="text/javascript" src="./js/maptalks.js"></script>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/three@0.104.0/build/three.min.js"></script>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/maptalks.three@latest/dist/maptalks.three.js"></script>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/turf@7.0.0-alpha.1/dist/turf.js"></script>
    <script type="text/javascript" src="./js/geoutil.js"></script>
    <style>
        html,
        body {
            margin: 0px;
            height: 100%;
            width: 100%;
        }

        #map {
            width: 100%;
            height: 100%;
            background-color: #000;
        }
    </style>
</head>

<body>
    <div id="map"></div>
    <script>

        var map = new maptalks.Map("map", {
            center: [13.416935229170008, 52.529564137540376],
            zoom: 20,
            pitch: 70,
            bearing: 0,

            centerCross: true,
            doubleClickZoom: false,
            baseLayer: new maptalks.TileLayer("tile", {
                urlTemplate: "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png",
                subdomains: ["a", "b", "c", "d"],
                attribution:
                    '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>'
            })
        });

        var threeLayer = new maptalks.ThreeLayer("t", {
            forceRenderOnMoving: true,
            forceRenderOnRotating: true
            // animation: true
        });

        threeLayer.prepareToDraw = function (gl, scene, camera) {
            var light = new THREE.DirectionalLight(0xffffff);
            light.position.set(0, -10, 10).normalize();
            scene.add(light);
            addCircles();
        };
        threeLayer.addTo(map);

        map.on("click", (e) => {
            console.log(e.coordinate.toArray());
        });

        const lnglats = [
            [13.410053026493756, 52.57088363368021],
            [13.411244485152679, 52.56961198362464],
            [13.411736063139983, 52.568735840146786],
            [13.411969248649939, 52.56831580434661],
            [13.411930714958771, 52.568128081587844],
            [13.412133765767294, 52.567353314537826],
            [13.4122821460262, 52.566209331390866],
            [13.412444545544304, 52.56481361534688],
            [13.412581926581083, 52.563693767515105],
            [13.412935727982244, 52.5611728580142],
            [13.413047650736644, 52.55976921762604],
            [13.415261226025109, 52.55973702758476],
            [13.416231189512132, 52.559740419161045],
            [13.416375531637414, 52.55978964259296],
            [13.418179305573858, 52.559765350331844],
            [13.41975452900681, 52.55972729555705],
            [13.420544646712642, 52.55973117152175],
            [13.421379877717527, 52.55972761264965],
            [13.422187773513201, 52.559824743857206],
            [13.422268628199504, 52.559833185348026],
            [13.422315244391712, 52.55975261712237],
            [13.422441845178923, 52.55935310867224],
            [13.422571505714814, 52.55897036605066],
            [13.422687876599412, 52.55863798044939],
            [13.42271669844854, 52.55855333616509],
            [13.42281717610149, 52.55807012882812],
            [13.422850423714067, 52.557929916503014]
        ];

        var tripBox;
        function addCircles() {
            const lineString = new maptalks.LineString(lnglats);
            const line = threeLayer.toLine(lineString, {}, new THREE.LineBasicMaterial());
            tripBox = new TripBox(
                lineString,
                {},
                new THREE.MeshPhongMaterial({
                    color: "red"
                }),
                threeLayer
            );
            threeLayer.addMesh(tripBox).addMesh(line);
            map.setCenter(lineString.getCoordinates()[0]);
            animation();
            initGui();
        }

        function animation() {
            // layer animation support Skipping frames
            threeLayer._needsUpdate = !threeLayer._needsUpdate;
            if (threeLayer._needsUpdate) {
                threeLayer.renderScene();
            }
            requestAnimationFrame(animation);
        }

        function initGui() {
            var params = {
                add: true,
                play: tripBox.getOptions().play,
                trip: tripBox.getOptions().trip,
                rotation: tripBox.getOptions().trip,
                altitude: 0
            };

            var gui = new dat.GUI();
            gui.add(params, "add").onChange(function () {
                if (params.add) {
                    threeLayer.addMesh(tripBox);
                } else {
                    threeLayer.removeMesh(tripBox);
                }
            });

            gui.add(params, "play").onChange(function () {
                tripBox.options.play = params.play;
            });
            gui.add(params, "trip").onChange(function () {
                tripBox.options.trip = params.trip;
            });

            gui.add(params, "rotation").onChange(function () {
                tripBox.options.rotation = params.rotation;
            });
        }

        //default values
        var OPTIONS = {
            altitude: 0,
            trip: false,
            rotation: false,
            play: true,
            chunkLength: 1
        };

        /**
         * custom  component
         *
         * you can customize your own components
         * */

        class TripBox extends maptalks.BaseObject {
            constructor(lineString, options, material, layer) {
                options = maptalks.Util.extend({}, OPTIONS, options, { layer, lineString });
                super();
                //Initialize internal configuration
                // https://github.com/maptalks/maptalks.three/blob/1e45f5238f500225ada1deb09b8bab18c1b52cf2/src/BaseObject.js#L135
                this._initOptions(options);
                const { altitude, chunkLength } = options;
                //generate geometry

                const geometry = new THREE.BoxBufferGeometry(0.1, 0.2, 0.01);

                //Initialize internal object3d
                // https://github.com/maptalks/maptalks.three/blob/1e45f5238f500225ada1deb09b8bab18c1b52cf2/src/BaseObject.js#L140
                this._createMesh(geometry, material);

                //set object3d position
                const z = layer.distanceToVector3(altitude, altitude).x;
                const position = layer.coordinateToVector3(
                    lineString.getCoordinates()[0],
                    z
                );
                this.getObject3d().position.copy(position);
                this._calTripData(layer);
                this.on("remove", () => {
                    this.getMap().config("draggable", true);
                });
                // this.getObject3d().rotation.x = -Math.PI;
            }

            _calTripData(layer) {
                const { lineString, chunkLength } = this.getOptions();
                const lines = lineSlice(lineString, chunkLength);
                const first = lines[0][0];
                const v = layer.coordinateToVector3(first);
                const coordinates = [first],
                    positions = [v];
                lines.forEach((line) => {
                    for (let i = 0; i < line.length; i++) {
                        const coordinate = line[i];
                        if (
                            coordinate.join(",").toString() ===
                            coordinates[coordinates.length - 1].join(",").toString()
                        ) {
                            continue;
                        }
                        coordinates.push(coordinate);
                        const v = layer.coordinateToVector3(coordinate);
                        positions.push(v);
                    }
                });
                console.log(coordinates);
                const bearings = [];
                for (let i = 0; i < coordinates.length - 1; i++) {
                    const coordinate = coordinates[i];
                    const nextcoordinate = coordinates[i + 1];
                    var point1 = turf.point(coordinate);
                    var point2 = turf.point(nextcoordinate);
                    var bearing = turf.bearing(point1, point2);
                    bearings.push((-bearing * Math.PI) / 180);
                }
                console.log(bearings);
                this._tripCoordinates = coordinates;
                this._positions = positions;
                this._bearings = bearings;
                this._idx = -1;
                this._rotating = false;
            }

            _animation() {
                const { play, trip, rotation } = this.getOptions();
                if (!play) {
                    this.getMap().config("draggable", true);
                    return;
                }
                const { _tripCoordinates, _bearings, _idx, _positions } = this;
                this._idx++;
                this.getObject3d().position.copy(_positions[this._idx]);
                if (this._idx >= _tripCoordinates.length - 1) {
                    this._idx = -1;
                }
                if (trip) {
                    this.getMap().config("draggable", false);
                    this.getMap().setCenter(_tripCoordinates[this._idx]);
                } else {
                    this.getMap().config("draggable", true);
                }
                const bearing = _bearings[this._idx];
                if (bearing != undefined) {
                    this.getObject3d().rotation.z = bearing;
                    if (rotation) {
                        this.getMap().config("draggable", false);
                        if (this._rotating) {
                            return;
                        }
                        if (Math.abs(bearing) >= Math.PI / 3) {
                            const view = Object.assign({}, map.getView(), {
                                bearing: Math.abs((bearing / Math.PI) * 180)
                            });
                            this._rotating = true;
                            map.animateTo(
                                view,
                                {
                                    duration: 600
                                },
                                (frame) => {
                                    if (frame.state.playState === "finished") {
                                        this._rotating = false;
                                    }
                                }
                            );
                        }
                    } else {
                        this.getMap().config("draggable", true);
                    }
                }
            }
        }


    </script>
</body>

</html>